package com.ydl.shopping.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ydl.shopping.core.enums.ResultEnum;
import com.ydl.shopping.domain.TbMenu;
import com.ydl.shopping.domain.TbRole;
import com.ydl.shopping.domain.TbRoleMenu;
import com.ydl.shopping.exception.ServiceException;
import com.ydl.shopping.mapper.TbRoleMenuMapper;
import com.ydl.shopping.service.ITbMenuService;
import com.ydl.shopping.service.ITbRoleMenuService;
import com.ydl.shopping.service.ITbRoleService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class TbRoleMenuServiceImpl extends ServiceImpl<TbRoleMenuMapper, TbRoleMenu> implements ITbRoleMenuService {
    private final ITbRoleService tbRoleService;

    @Resource
    private ITbMenuService tbMenuService;

    public TbRoleMenuServiceImpl(@Lazy ITbRoleService tbRoleService) {
        this.tbRoleService = tbRoleService;
    }

    @Override
    public String saveRoleMenu(Long roleId, List<Long> menuIds) {
        TbRole sysRole = tbRoleService.getById(roleId);
        if (sysRole == null) {
            return "用户不存在";
        }
        // 判断是否空权
        if (menuIds.isEmpty()) {
            return null;
        }
        // 获取角色所有菜单ID
        ArrayList<Long> roles = new ArrayList<>();
        roles.add(roleId);
        List<Long> roleMenuIds = getRoleMenuIds(roles);

        // 先取出相同值 a与b的交集 获取要保留的 retainIds
        Collection<Long> retainIds = CollectionUtils.intersection(roleMenuIds, menuIds);
        // 再取出不同值 a与retainIds的差集 获取要删除的 deleteIds
        Collection<Long> deleteIds = CollectionUtils.subtract(roleMenuIds, retainIds);
        for (Long menuId : deleteIds) {
            Long roleMenuId = getRoleMenuId(roleId, menuId);
            if (roleMenuId == null) {
                continue;
            }
            boolean delResult = removeById(roleMenuId);
            if (!delResult) {
                throw new ServiceException(ResultEnum.ERROR);
            }
        }

        // 再取出不同值 b与retainIds的差集 获取要新增的 saveIds
        Collection<Long> saveIds = CollectionUtils.subtract(menuIds, retainIds);

        for (Long menuId : saveIds) {
            TbMenu sysMenu = tbMenuService.getById(menuId);
            if (sysMenu == null) {
                continue;
            }
            boolean saveResult = save(new TbRoleMenu(roleId, menuId));
            if (!saveResult) {
                throw new ServiceException(ResultEnum.ERROR);
            }
        }
        return null;
    }

    /**
     * 获取角色菜单ID
     *
     * @param roleId 角色ID
     * @param menuId 菜单ID
     * @return 角色菜单ID/null
     */
    private Long getRoleMenuId(Long roleId, Long menuId) {
        TbRoleMenu tbRoleMenu = query().eq("role_id", roleId).eq("menu_id", menuId).one();
        if (tbRoleMenu == null) {
            return null;
        }
        return tbRoleMenu.getId();
    }

    /**
     * 获取角色所有角色菜单IDs
     *
     * @param roleId 角色ID
     * @return 角色菜单IDs
     */
    private List<Long> getIds(Long roleId) {
        List<TbRoleMenu> roleMenus = query().eq("role_id", roleId).list();
        return roleMenus.stream().map(TbRoleMenu::getId).collect(Collectors.toList());
    }

    @Override
    public List<Long> getRoleMenuIds(List<Long> roleIds) {
        if (roleIds.contains(1L)) {
            List<TbMenu> list = tbMenuService.list();
            return list.stream().map(TbMenu::getId).collect(Collectors.toList());
        }
        List<TbRoleMenu> roleMenus = query().select("DISTINCT(menu_id)").in("role_id", roleIds).list();
        return roleMenus.stream().map(TbRoleMenu::getMenuId).collect(Collectors.toList());
    }
}
